import serial
import serial.tools.list_ports
import threading
from time import time, sleep

class SerialPortLogic:
    def __init__(self, ui):
        self.ui = ui
        self.serial_connection = None
        self.is_listening = False

        self.ui.set_serial_ports(self.get_serial_ports())  # 设置串口下拉框的可选项
        self.ui.set_toggle_button_command(self.toggle_serial)  # 设置打开/关闭串口按钮的命令
        self.ui.set_send_button_command(self.send_data)  # 设置发送按钮的命令

    def get_serial_ports(self):
        """获取可用的串口列表"""
        return serial.tools.list_ports.comports()

    def start_listening(self):
        """启动监听线程，用于接收串口数据"""
        self.is_listening = True
        self.listen_thread = threading.Thread(target=self.listen_serial, daemon=True)
        self.listen_thread.start()

    def stop_listening(self):
        """停止监听线程"""
        self.is_listening = False

    def listen_serial(self):
        """监听串口数据并更新到接收文本框"""
        buffer = '' # 清空缓冲区
        last_received_time = time()  # 记录最后接收数据的时间
        while self.is_listening and self.serial_connection and self.serial_connection.is_open:
            try:
                if self.serial_connection.in_waiting > 0:  # 检查是否有数据可读
                    data = self.serial_connection.read(self.serial_connection.in_waiting).decode('utf-8')
                    if data:
                        buffer += data  # 将接收到的数据添加到缓冲区
                        last_received_time = time()  # 更新最后接收时间
                        # if data == '\n':  # 检测到回车符
                        #     self.ui.set_receive_text(buffer)  # 更新接收文本框
                        #     buffer = ''
                else:
                    if time() - last_received_time > 0.002:  # 检查是否超过2ms未接收到数据
                        if buffer:  # 如果缓冲区有数据
                            self.ui.set_receive_text(buffer)  # 更新接收文本框
                            buffer = ''  # 清空缓冲区
                    sleep(0.001)  # 减少CPU占用
            except Exception as e:
                self.ui.set_receive_text(f"接收错误：{e}")  # 更新接收文本框

    def toggle_serial(self):
        """打开或关闭串口"""
        if self.serial_connection and self.serial_connection.is_open:
            self.close_serial()
        else:
            self.open_serial()

    def open_serial(self):
        """打开串口连接"""
        port = self.ui.get_serial_settings()["port"]
        baudrate = self.ui.get_serial_settings()["baudrate"]
        data_bits = self.ui.get_serial_settings()["data_bits"]
        parity = self.ui.get_serial_settings()["parity"]
        stop_bits = self.ui.get_serial_settings()["stop_bits"]

        if not port:
            self.ui.messagebox("错误", "请选择一个串口！")
            return
        try:
            self.serial_connection = serial.Serial(
                port=port,
                baudrate=int(baudrate),
                bytesize=int(data_bits),
                parity=serial.PARITY_NONE if parity == "None" else parity[0],
                stopbits=float(stop_bits),
                timeout=1
            )
            self.ui.set_toggle_button_text("关闭串口")  # 更新按钮文本
            self.start_listening()  # 开始监听串口数据
        except Exception as e:
            self.ui.messagebox("错误", f"无法打开串口：{e}")

    def close_serial(self):
        """关闭串口连接"""
        self.stop_listening()  # 停止监听串口数据
        if self.serial_connection and self.serial_connection.is_open:
            self.serial_connection.close()
            self.ui.set_toggle_button_text("打开串口")  # 更新按钮文本

    def send_data(self):
        """发送数据到串口"""
        if not self.serial_connection or not self.serial_connection.is_open:
            self.ui.messagebox("错误", "串口未打开！",'error')
            return
        data = self.ui.get_send_data()
        if data != "":
            self.serial_connection.write(data.encode()+b'\n')  # 发送数据并添加回车换行符
        else:
             self.serial_connection.write("\n".encode())  # 发送换行符
